#include "..\include\Input.h"
#include <Windows.h>
#include <dinput.h>


using namespace Boon;

#define KEY_PRESSED 0x80
#define SAFE_RELEASE(p) { if(p) { (p)->Unacquire(); (p)->Release(); (p)=NULL; } }

Command gEmpty( "N/A" );
HWND GetHWND();

LPDIRECTINPUT8			gDInput = nullptr;	// pointer to direct input object
LPDIRECTINPUTDEVICE8	gDeviceKeyboard	= nullptr;	// pointer to keyboard device
LPDIRECTINPUTDEVICE8	gDeviceMouse = nullptr;	// pointer to mouse device
HINSTANCE				gInstance = nullptr;

void Boon::Input::OnInitialize()
{

	BoonException e( "Input", "OnInitialize", "Could not create input device!" );
	if( FAILED( DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&gDInput, nullptr ) ) )
		throw e;
	if( FAILED( gDInput->CreateDevice( GUID_SysKeyboard, &gDeviceKeyboard, nullptr ) ) )
		throw e;
	if( FAILED( gDeviceKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
		throw e;
	if( FAILED( gDeviceKeyboard->SetCooperativeLevel( GetHWND(), DISCL_NONEXCLUSIVE | DISCL_FOREGROUND ) ) )
		throw e;
	gDeviceKeyboard->Acquire();
}

void Boon::Input::OnDestroy()
{
	SAFE_RELEASE( gDeviceKeyboard )
	SAFE_RELEASE( gDeviceMouse )
	if( gDInput )
		gDInput->Release();
}

void Boon::Input::Update()
{
	unsigned char states[256];
	if( FAILED( gDeviceKeyboard->Poll() ) )
	{
		while( gDeviceKeyboard->Acquire() == DIERR_INPUTLOST )
		{}
		return;
	}

	gDeviceKeyboard->GetDeviceState( sizeof( states ), &states );

	auto iter = m_Commands.begin();
	auto end = m_Commands.end();

	for( ; iter != end; ++iter )
	{
		iter->second.SetEnabled( states[(*iter).first] == KEY_PRESSED );
	}
}

bool Boon::Input::AddCommand( const char* name, KeyCode key, Command** outCommand )
{
	auto result = m_Commands.find( key );
	if( result == m_Commands.end() )
	{
		Command* added = &m_Commands.insert( m_Commands.begin(), CommandsPair( key, Command( name ) ) )->second;
		if( outCommand )
			*outCommand = added;
		return true;
	}
	outCommand = nullptr;
	return false;
}

const Command& Boon::Input::GetCommand( KeyCode key ) const
{
	auto result = m_Commands.find( key );
	if( result != m_Commands.end() )
		return result->second;
	return gEmpty;
}
